
import { parseHTML } from "./parse";

// 匹配胡须语法 {{}}
const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g;

function genProps(attrs) {
    let props = '';
    attrs.forEach(attr => {
        switch (attr.key) {
            case 'style':
                let obj = {}
                attr.value.split(';').forEach(item => {
                    if (item) {
                        let [key, value] = item.split(':');
                        obj[key] = value.trim();
                    }
                })
                attr.value = obj
                break;
        }
        props += `${attr.key}: ${JSON.stringify(attr.value)}, `;
    });
    return `{ ${props.slice(0, -2)} }`;
}

function gen(node) {
    switch (node.type) {
        case 1:
            // 标签节点
            return generate(node);
        case 3:
            // 文本节点
            let text = node.text;

            // 匹配 {{}}
            if (!defaultTagRE.test(text)) {
                return '_v(' + JSON.stringify(text) + ')';
            } else {
                let tokens = [], match, lastIndex = 0;
                // exec 匹配全局（g）正则时，在第一次匹配完毕会继续按照索引继续匹配，所以需要重置索引
                defaultTagRE.lastIndex = 0;
                while (match = defaultTagRE.exec(text)) {

                    // {{ name }} Hello {{ age }} Hello 

                    let index = match.index;

                    // 匹配胡须语法中间的文本字符
                    if (index > lastIndex) {
                        tokens.push(JSON.stringify(text.slice(lastIndex, index)));
                    }

                    // 匹配到的胡须语法
                    tokens.push(`_s(${match[1].trim()})`)

                    // 更新索引
                    lastIndex = index + match[0].length;
                }

                // 匹配到最后一个胡须语法与文本
                if (lastIndex < text.length) {
                    tokens.push(JSON.stringify(text.slice(lastIndex)));
                }

                return '_v(' + tokens.join('+') + ')';
            }
        case 8:
            // 注释节点
            return '_e(' + JSON.stringify(node.comment) + ')';
        default:
            return '';
    }
}

function genChildren(children) {
    return children.map(child => gen(child))?.join(',');
}

function generate(ast) {
    /*
        render() {
            return _c(
                'div', 
                { id: 'app' },
                _c(
                    'div', 
                    { style: { color: 'red' } }, 
                    _v(_s(name)+'Hello'),
                ),
                _c(
                    'span', 
                    undefined,
                    _v(_s(age)),
                )
            );
        }
    */
    let code = (
        '_c('
        + JSON.stringify(ast.tag) + ','
        + (ast.attrs.length ? genProps(ast.attrs) : undefined)
        + (ast.children.length ? ',' + genChildren(ast.children) : '')
        + ')'
    )
    return code;
}


export function compileToFunctions(template) {
    // 1.将 template 转换成 AST 语法树
    /*
        AST是语法层面转换（这里是将HTML语法转换成JS语法），
        它描述语法本身，不是解析器，解析器是将语法转换成JS代码，
        所以描述的过程不能增加自定义属性。
    */
    let ast = parseHTML(template.trim());

    // 2.生成 render 方法（render 方法执行后的返回结果就是虚拟DOM）
    let code = `with(this) { return ${generate(ast)} }`;

    let render = new Function(code);

    return render;
}